<?php
/**
 * Created by PhpStorm.
 * User: admin
 * Date: 2019/10/21
 * Time: 16:31
 */

namespace app\adminapiv3\service;


use app\common\model\Ip;
use app\common\service\JwtToken;
use app\common\service\platform_manage\account\ServerUserService;
use app\common\service\ServerLoginLog;
use think\Db;


class LoginService extends BaseService
{
    private $loginUser = array();

    /**
     * @name 登录
     * @param $name
     * @param $password
     * @param $captchaCode
     * @author wx
     * @date 2019/10/21 16:32
     */
    public function login($userName, $password, $captchaCode)
    {

        //1. 白名单验证
        $userIp = $_SERVER['REMOTE_ADDR'];

        if (!$this->checkIp($userIp)) {
            return false;
        }


        //2. 验证码验证
        if (!$this->checkCaptcha($captchaCode)) {

            return false;
        }

        //3. 查找用户数据
        if (!$this->checkUser($userName)) {
            return false;
        }

        //4. 检查今日登录失败次数
        if (!$this->checkErrorLogin()) {
            return false;
        }


        // //5. 验证密码
        if (!$this->checkPassword($password)) {
            return false;
        }

        //6. 登录成功,返回数据
        return $this->returnData();

    }

    /**
     * @name ip白名单验证
     * @author wx
     * @date 2019/10/21 16:37
     */
    public function checkIp($userIp)
    {
        $allowIpObj = new \app\common\service\platform_manage\ServerAllowIpService();
        $condition['ip'] = $userIp;

        //1. 验证是否需要验证ip
        $fileName = '../runtime/config/allow_ip.conf';


        if (file_exists($fileName)) {
            $allowConfig = file_get_contents($fileName);
            $allowArr = json_decode($allowConfig, true);

            if($allowArr['status'] == 1){//1为开启ip白名单自动加入,0为手动

                $timeRangeArr = array(
                    0 => 0,
                    1 => 1800,
                    2 => 3600,
                    3 => 8*3600,
                    4 => 16*3600,
                );

                $nowTime = time();
                $time = $timeRangeArr[$allowArr['time_range']];

                if($time == 0 || $nowTime <= $allowArr['start_time'] + $time){//不验证白名单
                    //添加当前ip到ip白名单中
                    $ipInfo = $allowIpObj->findData($condition);
                    if(!$ipInfo){
                        $addData['ip'] = $_SERVER['REMOTE_ADDR'];
                        $addData['ctime'] = time();
                        $addData['login_time'] = time();

                        $allowIpObj->add($addData);

                        return true;
                    }
                }
            }
        }

        //2. 验证ip
        $ipInfo = $allowIpObj->findData($condition);

        if(!$ipInfo){
            $this->setError($this->CODE_FAIL, '非法登录系统');
            return false;
        }


        return true;
    }

    /**
     * @name 验证验证码
     * @param $captchaCode
     * @return bool
     * @author wx
     * @date 2019/10/22 11:24
     */
    public function checkCaptcha($captchaCode)
    {

        $randCodeServer = new \app\common\service\ServerRandCode();
        $codeInfo = $randCodeServer->findData(['ip' => $_SERVER['REMOTE_ADDR'], 'code' => $captchaCode]);

        if(!$codeInfo){
            $this->setError($this->CODE_FAIL, '验证码输入错误');
            return false;
        }

        return true;
    }

    /**
     * @name 查找用户
     * @param $userName
     * @return bool
     * @author wx
     * @date 2020/10/26 14:34
     */
    public function checkUser($userName)
    {
        $userServer = new ServerUserService();
        $userInfo = $userServer->findData(['real_name' => $userName]);
        if(!$userInfo){
            $this->setError($this->CODE_FAIL, '用户不存在');
            return false;
        }

        //权限为空,则不让登录
        $rbacInfo = \model('ServerUserGroupMapping')->getRbacInfo($userInfo);
        if(!$rbacInfo['rbac']['auths']){
            $this->setError($this->CODE_FAIL, '您没有权限登录');
            return false;
        }

        $this->loginUser = $userInfo;

        return true;
    }

    /**
     * @name 检查用户登录错误次数
     * @param $userInfo
     * @return bool
     * @author wx
     * @date 2019/11/27 13:23
     */
    public function checkErrorLogin()
    {
        $count_where['user_id'] = $this->loginUser['id'];
        $count_where['login_ip'] = $_SERVER['REMOTE_ADDR'];
        $count_where['ymd'] = date('Ymd');

        $loginLogServer = new ServerLoginLog();
        //查询今日最早登录错误的时间
        $errorInfo = $loginLogServer->findData($count_where);

        if(empty($errorInfo)){//今日没有登录错误
            return true;
        }

        //查询登录失败配置
        $loginFailConfFile = '../runtime/config/login.conf';
        if (!file_exists($loginFailConfFile)) {
            $loginFailSetting['fail_count'] = 5;
            $loginFailSetting['fail_time'] = 86400;
        }else{
            $loginFailConf = file_get_contents($loginFailConfFile);
            $loginFailSetting = json_decode($loginFailConf, true);

            $loginFailSetting['fail_count'] = empty($loginFailSetting['fail_count']) ? 5 : $loginFailSetting['fail_count'];
            $loginFailSetting['fail_time'] = empty($loginFailSetting['fail_time']) ? 86400 : $loginFailSetting['fail_time'];
        }

        if($errorInfo['login_time'] + $loginFailSetting['fail_time'] <= time()){
            //过了登录错误的时间限制了,应该清空此用户当天登录错误数据
            $delWhere['user_id'] = $this->loginUser['id'];
            $delWhere['ymd'] = date('Ymd');
            $loginLogServer->del($delWhere);
        }

        //用户登录失败次数
        $errorCount = $loginLogServer->findCount($count_where);

        if ($errorCount >= $loginFailSetting['fail_count']) {


            $failTime = $loginFailSetting['fail_time'] / 3600;

            if($failTime < 1){
                $failTime = $failTime * 60 .'分钟';
            }else{
                $failTime = $failTime .'小时';
            }


            $this->setError($this->CODE_FAIL, '今日登录失败超过'.$loginFailSetting['fail_count'].'次，请于'.$failTime.'后再次登录');
            return false;
        }

        return true;
    }

    /**
     * @name 验证密码
     * @param $password
     * @Author wx
     * @date 2019/4/19 15:46
     */
    public function checkPassword($password)
    {
        //更新ip白名单的登录时间
        Db::name('server_allow_ip')->where(['ip' => $_SERVER['REMOTE_ADDR']])->update(['login_time' => time()]);

        $userServer = new ServerUserService();
        //验证密码
        $passwordServer = new Password();


        $checkRes = $this->toDo([$passwordServer, 'decrypt'], [$password, $this->loginUser['salt'], $this->loginUser['password']]);


        if($checkRes){

            //修改最后一次登录时间
            $userUpdate['last_login_time'] = time();
            $userUpdate['last_login_ip'] = $_SERVER['REMOTE_ADDR'];

            $userServer->modify(['id' => $this->loginUser['id']], $userUpdate);
            return true;
        }else{

            $loginLogServer = new ServerLoginLog();
            $addData['user_id'] = $this->loginUser['id'];
            $addData['login_ip'] = $_SERVER['REMOTE_ADDR'];
            $addData['login_time'] = time();
            $addData['ymd'] = date('Ymd');
            $loginLogServer->add($addData);

            $this->setError($this->CODE_FAIL,'用户名或者密码错误');
            return false;
        }
    }

    /**
     * 下发token,返回数据
    */
    public function returnData()
    {
        //登录成功,返回数据
        $data = array(
            'id' => $this->loginUser['id'],
            'show_name' => $this->loginUser['show_name'],
            'real_name' => $this->loginUser['real_name'],
            'login_ip' => $_SERVER['REMOTE_ADDR'],
        );

        $jwt = JwtToken::getToken($data);

        return ['token' => $jwt, 'show_name' => $this->loginUser['show_name']];
    }

    /**
     *  加入用户日志
     */
    public function __destruct()
    {
        global $errCode;
        global $errMsg;

        if(!empty($this->loginUser)){
            $content = '系统登录';
            $status = 1;
            if($errCode != $this->CODE_SUCCESS){
                $content.= ' [ 失败原因：'.$errMsg.']';
                $status = 0;
            }

            //1. 查询ip对应的地址address
            $addressR = $_SERVER['DOCUMENT_ROOT'].'/static/IP/qqzeng.dat';
            if(!file_exists($addressR))
            {
                return true;
            }
            $ipServer = new Ip($addressR);
            $ipInfo = $ipServer->getlocation($_SERVER['REMOTE_ADDR']);
            if($ipInfo){
                $address = $ipInfo['country'].$ipInfo['province'].$ipInfo['city'].$ipInfo['area'];
            }else{
                $address = '保留';
            }

            Db::name('server_option_history')->insert([
                'type' => 1,
                'content' => $content,
                'ip' => $_SERVER['REMOTE_ADDR'],
                'address' => $address,
                'user_id' => $this->loginUser['id'],
                'ctime' => time(),
                'status' => $status,
            ]);
        }

    }
}